Kaynak yükleme hatalarını zarifçe yönetmek, kullanıcı deneyimini ve uygulama kararlılığını iyileştirmek için React Hata Sınırlarını (Error Boundaries) hooks ile nasıl uygulayacağınızı öğrenin.
React'te Sağlam Kaynak Yükleme: Hooks ile Hata Sınırlarında (Error Boundaries) Ustalaşma
Modern web uygulamalarında, kaynakları asenkron olarak yüklemek yaygın bir uygulamadır. İster bir API'den veri çekmek, ister görselleri yüklemek veya modülleri içe aktarmak olsun, kaynak yüklemesi sırasında olası hataları yönetmek, sorunsuz bir kullanıcı deneyimi için çok önemlidir. React Hata Sınırları (Error Boundaries), alt bileşen ağacının herhangi bir yerindeki JavaScript hatalarını yakalamak, bu hataları kaydetmek ve tüm uygulamanın çökmesi yerine bir yedek arayüz (fallback UI) göstermek için bir mekanizma sağlar. Bu makale, kaynak yükleme hatalarını yönetmek için React Hooks ile birlikte Hata Sınırlarının nasıl etkili bir şekilde kullanılacağını incelemektedir.
Hata Sınırlarını (Error Boundaries) Anlamak
React 16'dan önce, bileşen render işlemi sırasında işlenmeyen JavaScript hataları React'in dahili durumunu bozar ve sonraki render işlemlerinde anlaşılmaz hatalara neden olurdu. Hata Sınırları, alt bileşenlerinde meydana gelen hatalar için genel bir yakalama bloğu (catch-all) görevi görerek bu sorunu çözer. Bunlar, aşağıdaki yaşam döngüsü yöntemlerinden birini veya her ikisini birden uygulayan React bileşenleridir:
static getDerivedStateFromError(error): Bu statik yöntem, bir alt bileşen tarafından bir hata fırlatıldıktan sonra çağrılır. Fırlatılan hatayı bir argüman olarak alır ve bileşenin durumunu güncellemek için bir değer döndürür.componentDidCatch(error, info): Bu yaşam döngüsü yöntemi, bir alt bileşen tarafından bir hata fırlatıldıktan sonra çağrılır. Fırlatılan hatayı bir argüman olarak ve ayrıca hatayı hangi bileşenin fırlattığı hakkında bilgi içeren bir nesneyi alır. Hata bilgilerini kaydetmek için kullanabilirsiniz.
Önemli bir nokta olarak, Hata Sınırları yalnızca altlarındaki tüm ağacın render aşamasındaki, yaşam döngüsü yöntemlerindeki ve kurucularındaki hataları yakalar. Aşağıdakiler için hataları yakalamazlar:
- Olay yöneticileri (event handlers) (daha fazla bilgi için aşağıdaki bölüme bakın)
- Asenkron kod (örn.
setTimeoutveyarequestAnimationFramegeri aramaları) - Sunucu tarafı render (server-side rendering)
- Hata Sınırının kendisinde fırlatılan hatalar (çocukları yerine)
Hata Sınırları ve React Hooks: Güçlü Bir Kombinasyon
Hata Sınırlarını uygulamak için geleneksel olarak sınıf bileşenleri kullanılırken, React Hooks daha öz ve fonksiyonel bir yaklaşım sunar. Hata yönetimi mantığını kapsayan ve kaynak yüklemesi sırasında hata fırlatabilecek bileşenleri sarmak için uygun bir yol sağlayan yeniden kullanılabilir bir useErrorBoundary hook'u oluşturabiliriz.
Özel bir useErrorBoundary Hook'u Oluşturma
İşte bir useErrorBoundary hook'u örneği:
import { useState, useCallback } from 'react';
function useErrorBoundary() {
const [error, setError] = useState(null);
const resetError = useCallback(() => {
setError(null);
}, []);
const captureError = useCallback((e) => {
setError(e);
}, []);
const ErrorBoundary = useCallback(({ children, fallback }) => {
if (error) {
return fallback ? fallback : An error occurred: {error.message || String(error)};
}
return children;
}, [error]);
return { ErrorBoundary, captureError, error, resetError };
}
export default useErrorBoundary;
Açıklama:
useState: Hata durumunu yönetmek içinuseStatekullanırız. Başlangıçta hatayınullolarak ayarlar.useCallback:resetErrorvecaptureErrorfonksiyonlarını hafızaya almak (memoize) içinuseCallbackkullanırız. Bu, bu fonksiyonlar prop olarak aktarılırsa gereksiz yeniden render'ları önlemek için iyi bir uygulamadır.ErrorBoundaryBileşeni: Bu,useCallbackile oluşturulmuş,childrenve isteğe bağlı birfallbackprop'u alan fonksiyonel bir bileşendir. Durumda bir hata varsa, ya sağlananfallbackbileşenini ya da varsayılan bir hata mesajını render eder. Aksi takdirde, çocukları render eder. Bu, bizim Hata Sınırımız olarak işlev görür. Bağımlılık dizisi `[error]`, `error` durumu değiştiğinde yeniden render edilmesini sağlar.captureErrorFonksiyonu: Bu fonksiyon, hata durumunu ayarlamak için kullanılır. Kaynakları yüklerken bunu birtry...catchbloğu içinde çağırırsınız.resetErrorFonksiyonu: Bu fonksiyon, hata durumunu temizler, bileşenin çocuklarını yeniden render etmesine (ve potansiyel olarak kaynak yüklemesini yeniden denemesine) olanak tanır.
Hata Yönetimi ile Kaynak Yükleme Uygulaması
Şimdi, bu hook'u kaynak yükleme hatalarını yönetmek için nasıl kullanacağımızı görelim. Bir API'den kullanıcı verilerini çeken bir bileşeni ele alalım:
import React, { useState, useEffect } from 'react';
import useErrorBoundary from './useErrorBoundary';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const { ErrorBoundary, captureError, error, resetError } = useErrorBoundary();
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setUser(data);
} catch (e) {
captureError(e);
}
};
fetchData();
}, [userId, captureError]);
if (error) {
return (
Failed to load user data. {user.name}
Email: {user.email}
{/* Other user details */}Açıklama:
useErrorBoundaryhook'unu içe aktarırız.ErrorBoundarybileşenini,captureErrorfonksiyonunu,errordurumunu veresetErrorfonksiyonunu almak için hook'u çağırırız.useEffecthook'u içinde, API çağrısını birtry...catchbloğuna sararız.- API çağrısı sırasında bir hata oluşursa, hata durumunu ayarlamak için
captureError(e)fonksiyonunu çağırırız. - Eğer
errordurumu ayarlanmışsa,ErrorBoundarybileşenini render ederiz. Bir hata mesajı ve "Yeniden Dene" düğmesi gösteren özel birfallbackprop'u sağlarız. Düğmeye tıklamak, hata durumunu temizlemek içinresetErrorfonksiyonunu çağırır, bu da yeniden render'ı tetikler ve verileri çekmek için başka bir deneme yapar. - Eğer hata oluşmadıysa ve kullanıcı verileri yüklendiyse, kullanıcı profili ayrıntılarını render ederiz.
Farklı Türdeki Kaynak Yükleme Hatalarını Yönetme
Farklı türdeki kaynak yükleme hataları, farklı yönetim stratejileri gerektirebilir. İşte bazı yaygın senaryolar ve bunların nasıl ele alınacağı:
Ağ Hataları
Ağ hataları, istemcinin sunucuya bağlanamadığı durumlarda (örneğin, bir ağ kesintisi veya sunucunun kapalı olması nedeniyle) meydana gelir. Yukarıdaki örnek, `response.ok` kullanarak temel ağ hatalarını zaten yönetmektedir. Daha gelişmiş hata tespiti eklemek isteyebilirsiniz, örneğin:
//Inside the fetchData function
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
// Consider adding specific error code handling
if (response.status === 404) {
throw new Error("User not found");
} else if (response.status >= 500) {
throw new Error("Server error. Please try again later.");
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
}
const data = await response.json();
setUser(data);
} catch (error) {
if (error.message === 'Failed to fetch') {
// Likely a network error
captureError(new Error('Network error. Please check your internet connection.'));
} else {
captureError(error);
}
}
Bu durumda, kullanıcıya bir ağ bağlantı sorunu olduğunu belirten bir mesaj gösterebilir ve internet bağlantılarını kontrol etmelerini önerebilirsiniz.
API Hataları
API hataları, sunucu bir hata yanıtı döndürdüğünde (örneğin, 400 Bad Request veya 500 Internal Server Error) meydana gelir. Yukarıda gösterildiği gibi, `response.status` değerini kontrol edebilir ve bu hataları uygun şekilde yönetebilirsiniz.
Veri Ayrıştırma Hataları
Veri ayrıştırma hataları, sunucudan gelen yanıtın beklenen formatta olmaması ve ayrıştırılamaması durumunda (örneğin, geçersiz JSON) meydana gelir. Bu hataları, response.json() çağrısını bir try...catch bloğuna sararak yönetebilirsiniz:
//Inside the fetchData function
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setUser(data);
} catch (error) {
if (error instanceof SyntaxError) {
captureError(new Error('Failed to parse data from server.'));
} else {
captureError(error);
}
}
Görsel Yükleme Hataları
Görsel yüklemesi için, <img> etiketindeki onError olay yöneticisini kullanabilirsiniz:
function MyImage({ src, alt }) {
const { ErrorBoundary, captureError } = useErrorBoundary();
const [imageLoaded, setImageLoaded] = useState(false);
const handleImageLoad = () => {
setImageLoaded(true);
};
const handleImageError = (e) => {
captureError(new Error(`Failed to load image: ${src}`));
};
return (
Failed to load image.